import { Table as AntdTable, TableProps as AntdTableProps, Button, message, PaginationProps, Popconfirm, Space } from "antd";
import { ColumnType } from "antd/es/table";
import { forwardRef, MouseEvent, ReactNode, Ref, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
import { IDParams, PageReq, PageResponse, Response } from "@/typings/api";
import { cloneDeep } from "lodash";
import { EditOutlined, DeleteOutlined, CopyOutlined } from "@ant-design/icons";
import { useNavigate } from "react-router";
import { AnyObject } from "antd/es/_util/type";
import { parseUnitToNumber } from "@/utils";
import AuthButton from "@/components/Button";

export interface TableProps<D extends AnyObject> extends Omit<AntdTableProps, "columns"> {
    _id?: string | null;
    getApi: (params: PageReq) => Promise<PageResponse<any>>;
    delApi?: (_id: string) => Promise<Response>;
    columns: (ColumnType<D> & { isTable?: boolean })[];
    onEdit?: (e: MouseEvent, record: Record<string, any>) => void;
    clonePathName?: string;
    actionMore?: (record: D) => ReactNode;
    updatePermission?: string;
    deletePermission?: string;
}

export interface TableRef {
    getList: (page?: number, pageSize?: number) => Promise<void>;
}

const Table = <D extends AnyObject = { _id: string } & Record<string, any>>(props: TableProps<D>, ref: Ref<TableRef>) => {
    const { columns, getApi, delApi, onEdit, clonePathName, actionMore, _id, updatePermission, deletePermission, ...remainingProps } = props;
    const navigate = useNavigate();
    const UpdateButton = useMemo(() => (updatePermission ? AuthButton : Button), [updatePermission]);
    const DeleteButton = useMemo(() => (deletePermission ? AuthButton : Button), [deletePermission]);
    const innerColumns = useMemo(() => {
        const list = cloneDeep(columns)
            .filter(item => item.isTable !== false)
            .map(item => {
                let minWidth = 120;
                if (item.dataIndex === "operation") minWidth = 200;
                if (["createdAt", "updatedAt"].includes(item.dataIndex?.toString() || "")) minWidth = 170;
                if (item.width) return { ...item };
                return { minWidth, ...item };
            });
        const operationColumn = list.find(item => item.dataIndex === "operation");
        if (operationColumn) {
            operationColumn.render = (_, record) => (
                <Space>
                    {actionMore?.(record)}
                    {clonePathName && (
                        <UpdateButton
                            size="small"
                            type="primary"
                            icon={<CopyOutlined />}
                            onClick={e => navigate(`${clonePathName}?cloneId=${record._id}`)}
                        >
                            克隆
                        </UpdateButton>
                    )}
                    {onEdit && (
                        <UpdateButton permission={updatePermission} size="small" type="primary" icon={<EditOutlined />} onClick={e => onEdit(e, record)}>
                            编辑
                        </UpdateButton>
                    )}
                    {delApi && (
                        <Popconfirm
                            title="确认删除这条数据吗？"
                            onConfirm={async () => {
                                const { message: msg } = await delApi(record._id);
                                getList();
                                message.success(msg);
                            }}
                        >
                            <DeleteButton permission={deletePermission} size="small" danger icon={<DeleteOutlined />}>
                                删除
                            </DeleteButton>
                        </Popconfirm>
                    )}
                </Space>
            );
        }
        return list;
    }, [columns]);

    const [dataSource, setDataSource] = useState<any[]>([]);
    const [pagination, setPagination] = useState<PaginationProps>({
        pageSize: 10,
        current: 1,
        total: 10,
        showTotal: (total, range) => `${range[0]}-${range[1]} / ${range[1] - range[0] + 1}条 / 共 ${total} 条`,
        onChange(page, pageSize) {
            getList(page, pageSize);
        },
    });
    const paginationRef = useRef<PaginationProps>(pagination);
    useEffect(() => {
        paginationRef.current = pagination;
    }, [pagination]);

    const [loading, setLoading] = useState(false);
    const getList = async (paramsPage?: number, paramsPageSize?: number) => {
        const { current, pageSize } = paginationRef.current;
        const finalPage = paramsPage ?? current!;
        const finalPageSize = paramsPageSize ?? pageSize!;
        setLoading(true);
        try {
            const params: PageReq<IDParams> = { page: finalPage, pageSize: finalPageSize };
            if (_id) params._id = _id;
            const { data: { list, total } = { list: [], total: 10 } } = await getApi(params);
            setDataSource(list);
            setPagination({
                ...paginationRef.current,
                current: finalPage,
                pageSize: finalPageSize,
                total,
            });
        } finally {
            setLoading(false);
        }
    };
    useEffect(() => {
        getList();
    }, []);

    useImperativeHandle(ref, () => ({
        getList,
    }));
    return (
        <AntdTable<D>
            loading={loading}
            scroll={{ x: columns.reduce((pre, item) => pre + parseUnitToNumber(item.width || item.minWidth), 0) }}
            tableLayout="auto"
            columns={innerColumns}
            dataSource={dataSource}
            pagination={pagination}
            rowKey="_id"
            {...remainingProps}
        />
    );
};

export default forwardRef(Table);
